Send power management events to the Trusted OS (TLK)
authorVarun Wadekar <[email protected]>
Wed, 26 Aug 2015 07:19:03 +0000 (12:49 +0530)
committerVarun Wadekar <[email protected]>
Wed, 30 Sep 2015 05:08:28 +0000 (10:38 +0530)
This patch adds PM handlers to TLKD for the system suspend/resume and
system poweroff/reset cases. TLK expects all SMCs through a single
handler, which then fork out into multiple handlers depending on the
SMC. We tap into the same single entrypoint by restoring the S-EL1
context before passing the PM event via register 'x0'. On completion
of the PM event, TLK sends a completion SMC and TLKD then moves on
with the PM process.

Signed-off-by: Varun Wadekar <[email protected]>
include/bl32/payloads/tlk.h
services/spd/tlkd/tlkd_main.c
services/spd/tlkd/tlkd_pm.c

index bdfcc9a399d05de6a1196531f5034120be50dde5..6ce1eb69ed68a6bdcdcc57ea3e6f325af998f19b 100644 (file)
@@ -43,6 +43,9 @@
 #define TLK_REGISTER_LOGBUF    TLK_TOS_STD_FID(0x1)
 #define TLK_REGISTER_REQBUF    TLK_TOS_STD_FID(0x2)
 #define TLK_RESUME_FID         TLK_TOS_STD_FID(0x100)
+#define TLK_SYSTEM_SUSPEND     TLK_TOS_STD_FID(0xE001)
+#define TLK_SYSTEM_RESUME      TLK_TOS_STD_FID(0xE002)
+#define TLK_SYSTEM_OFF         TLK_TOS_STD_FID(0xE003)
 
 /*
  * SMC function IDs that TLK uses to signal various forms of completions
@@ -52,6 +55,9 @@
 #define TLK_PREEMPTED          (0x32000002 | (1 << 31))
 #define TLK_ENTRY_DONE         (0x32000003 | (1 << 31))
 #define TLK_VA_TRANSLATE       (0x32000004 | (1 << 31))
+#define TLK_SUSPEND_DONE       (0x32000005 | (1 << 31))
+#define TLK_RESUME_DONE                (0x32000006 | (1 << 31))
+#define TLK_SYSTEM_OFF_DONE    (0x32000007 | (1 << 31))
 
 /*
  * Trusted Application specific function IDs
index 58a60464d6ab477cac991a51fc004014b7083697..f5dd74499f821aea3a30dac7b32a6540c0b35ede 100644 (file)
@@ -54,9 +54,9 @@
 extern const spd_pm_ops_t tlkd_pm_ops;
 
 /*******************************************************************************
- * Array to keep track of per-cpu Secure Payload state
+ * Per-cpu Secure Payload state
  ******************************************************************************/
-static tlk_context_t tlk_ctx;
+tlk_context_t tlk_ctx;
 
 /* TLK UID: RFC-4122 compliant UUID (version-5, sha-1) */
 DEFINE_SVC_UUID(tlk_uuid,
@@ -386,6 +386,31 @@ uint64_t tlkd_smc_handler(uint32_t smc_fid,
                 */
                tlkd_synchronous_sp_exit(&tlk_ctx, x1);
 
+       /*
+        * These function IDs are used only by TLK to indicate it has
+        * finished:
+        * 1. suspending itself after an earlier psci cpu_suspend
+        *    request.
+        * 2. resuming itself after an earlier psci cpu_suspend
+        *    request.
+        * 3. powering down after an earlier psci system_off/system_reset
+        *    request.
+        */
+       case TLK_SUSPEND_DONE:
+       case TLK_RESUME_DONE:
+       case TLK_SYSTEM_OFF_DONE:
+
+               if (ns)
+                       SMC_RET1(handle, SMC_UNK);
+
+               /*
+                * TLK reports completion. TLKD must have initiated the
+                * original request through a synchronous entry into the SP.
+                * Jump back to the original C runtime context, and pass x1 as
+                * return value to the caller
+                */
+               tlkd_synchronous_sp_exit(&tlk_ctx, x1);
+
        /*
         * Return the number of service function IDs implemented to
         * provide service to non-secure
index 5f2bae3158afee987813109f6a83425c6fab83ef..1eff0aad09aa3d4502dda68da9ff4ba52f14e421 100644 (file)
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <context_mgmt.h>
+#include <debug.h>
 #include <psci.h>
+#include <tlk.h>
+
+#include "tlkd_private.h"
+
+extern tlk_context_t tlk_ctx;
 
 #define MPIDR_CPU0     0x80000000
 
@@ -45,10 +55,102 @@ static int32_t cpu_migrate_info(uint64_t *resident_cpu)
        return PSCI_TOS_NOT_UP_MIG_CAP;
 }
 
+/*******************************************************************************
+ * This cpu is being suspended. Inform TLK of the SYSTEM_SUSPEND event, so
+ * that it can pass this information to its Trusted Apps.
+ ******************************************************************************/
+static void cpu_suspend_handler(uint64_t suspend_level)
+{
+       gp_regs_t *gp_regs;
+       int cpu = read_mpidr() & MPIDR_CPU_MASK;
+       int32_t rc = 0;
+
+       /*
+        * TLK runs only on CPU0 and suspends its Trusted Apps during
+        * SYSTEM_SUSPEND. It has no role to play during CPU_SUSPEND.
+        */
+       if ((cpu != 0) || (suspend_level != PLAT_MAX_PWR_LVL))
+               return;
+
+       /* pass system suspend event to TLK */
+       gp_regs = get_gpregs_ctx(&tlk_ctx.cpu_ctx);
+       write_ctx_reg(gp_regs, CTX_GPREG_X0, TLK_SYSTEM_SUSPEND);
+
+       /* Program the entry point and enter TLK */
+       rc = tlkd_synchronous_sp_entry(&tlk_ctx);
+
+       /*
+        * Read the response from TLK. A non-zero return means that
+        * something went wrong while communicating with it.
+        */
+       if (rc != 0)
+               panic();
+}
+
+/*******************************************************************************
+ * This cpu is being resumed. Inform TLK of the SYSTEM_SUSPEND exit, so
+ * that it can pass this information to its Trusted Apps.
+ ******************************************************************************/
+static void cpu_resume_handler(uint64_t suspend_level)
+{
+       gp_regs_t *gp_regs;
+       int cpu = read_mpidr() & MPIDR_CPU_MASK;
+       int32_t rc = 0;
+
+       /*
+        * TLK runs only on CPU0 and resumes its Trusted Apps during
+        * SYSTEM_SUSPEND exit. It has no role to play during CPU_SUSPEND
+        * exit.
+        */
+       if ((cpu != 0) || (suspend_level != PLAT_MAX_PWR_LVL))
+               return;
+
+       /* pass system resume event to TLK */
+       gp_regs = get_gpregs_ctx(&tlk_ctx.cpu_ctx);
+       write_ctx_reg(gp_regs, CTX_GPREG_X0, TLK_SYSTEM_RESUME);
+
+       /* Program the entry point and enter TLK */
+       rc = tlkd_synchronous_sp_entry(&tlk_ctx);
+
+       /*
+        * Read the response from TLK. A non-zero return means that
+        * something went wrong while communicating with it.
+        */
+       if (rc != 0)
+               panic();
+}
+
+/*******************************************************************************
+ * System is about to be reset. Inform the SP to allow any book-keeping
+ ******************************************************************************/
+static void system_off_handler(void)
+{
+       int cpu = read_mpidr() & MPIDR_CPU_MASK;
+       gp_regs_t *gp_regs;
+
+       /* TLK runs only on CPU0 */
+       if (cpu != 0)
+               return;
+
+       /* pass system off/reset events to TLK */
+       gp_regs = get_gpregs_ctx(&tlk_ctx.cpu_ctx);
+       write_ctx_reg(gp_regs, CTX_GPREG_X0, TLK_SYSTEM_OFF);
+
+       /*
+        * Enter the SP. We do not care about the return value because we
+        * must continue with the shutdown anyway.
+        */
+       (void)tlkd_synchronous_sp_entry(&tlk_ctx);
+}
+
 /*******************************************************************************
  * Structure populated by the Dispatcher to be given a chance to perform any
  * bookkeeping before PSCI executes a power mgmt.  operation.
  ******************************************************************************/
 const spd_pm_ops_t tlkd_pm_ops = {
        .svc_migrate_info = cpu_migrate_info,
+       .svc_suspend = cpu_suspend_handler,
+       .svc_suspend_finish = cpu_resume_handler,
+       .svc_system_off = system_off_handler,
+       .svc_system_reset = system_off_handler
 };